package cn.com.xy.sms.sdk.number;

import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.Map;

import org.json.JSONObject;

import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import cn.com.xy.sms.sdk.Iservice.XyCallBack;
import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.db.ContactsDBManager;
import cn.com.xy.sms.sdk.db.base.BaseManager;
import cn.com.xy.sms.sdk.db.entity.NumberInfoManager;
import cn.com.xy.sms.sdk.dex.DexUtil;
import cn.com.xy.sms.sdk.log.LogManager;
import cn.com.xy.sms.sdk.service.number.UpgradeNumberService;
import cn.com.xy.sms.sdk.util.CallBackState;
import cn.com.xy.sms.sdk.util.FileUtils;
import cn.com.xy.sms.sdk.util.MD5FileUtil;
import cn.com.xy.sms.sdk.util.ThreadPoolManager;
import cn.com.xy.sms.sdk.util.XyUtil;
import cn.com.xy.sms.util.EmbedNumberUtils;

public class UpgradeEmbedNumber {
    private static final String KEY_STATUS = "status";
    private static final String KEY_URL = "url";
    private static final String KEY_DATA_DIGEST = "dataDigest";
    private static final String KEY_DATA_VERSION = "dataVersion";
    private static final int STATUS_DATA_NOT_AVAILABLE = 204;
    private static final int STATUS_DATA_AVAILABLE = 200;
    private static final int STATUS_DATA_NOT_FOUND = 500;
    private static final int OTA_TYPE_ADD = 1;
    private static final int OTA_TYPE_MODIFY = 2;
    private static final int OTA_TYPE_REMOVE = 3;

    private static String mNewVersion = null;

    public static void upgrade(final XyCallBack callBack) {

        ThreadPoolManager.NUMBER_QUERY.execute(new Runnable() {

            @Override
            public void run() {
                queryByService(callBack);
            }
        });
    }

    private static void importEmbedNumberFileDataToDB(InputStream is) throws Exception {
        SQLiteDatabase db = null;
        LineNumberReader lineReader = null;
        try {
            db = ContactsDBManager.getSQLiteDatabase();
            JSONObject resultContainer = new JSONObject();
            Map<String, String> numberTagTypeMap = DexUtil.getNumberTagTypeMap(null);
            String line = null;
            lineReader = new LineNumberReader(new InputStreamReader(is));
            while ((line = lineReader.readLine()) != null) {
                int index = line.indexOf("\t");
                int type = Integer.parseInt(line.substring(0, index));
                String[] res = line.substring(index + 1).split("\t");
                if (OTA_TYPE_REMOVE == type) {
                    ContactsDBManager.delete(NumberInfoManager.TABLE_NAME, NumberInfoManager.NUM + "=?",
                            new String[] { res[0] });
                } else {
                    JSONObject numberData = EmbedNumberUtils.handleNumberData(resultContainer, numberTagTypeMap, res,
                            mNewVersion);
                    if (numberData == null) {
                        LogManager.e(Constant.TAG,
                                "UpgradeEmbedNumber importEmbedNumberFileDataToDB numberData == null: " + line);
                        continue;
                    }
                    /*IMOO-20 zhaojiangwei 20161221 start */
                    int t9Flag = InitEmbedNumber.getT9Flag(res, 6);
                    /*IMOO-20 zhaojiangwei 20161221 end */
                    if (OTA_TYPE_MODIFY == type) {
                        ContentValues values = BaseManager.getContentValues(null, NumberInfoManager.NUM, res[0], NumberInfoManager.RESULT, numberData.toString(), NumberInfoManager.VERSION,
                                mNewVersion, NumberInfoManager.FLAG_T9, String.valueOf(t9Flag));
                        ContactsDBManager.update(NumberInfoManager.TABLE_NAME, values, NumberInfoManager.NUM + "=?",
                                new String[] { res[0] });
                    } else if (OTA_TYPE_ADD == type) {
                        /* IMOO-14 likuangkuang 20161018 start */
                        // avoid insert fail while same record with 'no network info' or 'invalid network info' exists in database
                        NumberInfoManager.insertOrUpdate(res[0], numberData, mNewVersion, 0, t9Flag);
                        /* IMOO-14 likuangkuang 20161018 end */
                    }
                }
            }
        } catch (Throwable t) {
            LogManager.e(Constant.TAG, "UpgradeEmbedNumber import db exception" + t.getMessage(), t);
        } finally {
            ContactsDBManager.close(db);
            FileUtils.close(lineReader);
            FileUtils.close(is);
        }
    }

    private static String getZipDigest(String path) {
        String digest = null;
        File file = new File(path);
        if (file.exists()) {
            try {
                digest = MD5FileUtil.getFileMD5String(file);
            } catch (Throwable t) {
                LogManager.e(Constant.TAG, t.getMessage(), t);
            }
        }

        return digest;
    }

    private static void fetchAndUpdate(final XyCallBack callBack, JSONObject json) {
        final String url = json.optString(KEY_URL);
        final String digest = json.optString(KEY_DATA_DIGEST);
        mNewVersion = json.optString(KEY_DATA_VERSION);
        ThreadPoolManager.NUMBER_QUERY.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    String zipNumberFilePath = EmbedNumberUtils.getOTAZipFilePath();
                    String localDigest = getZipDigest(zipNumberFilePath);
                    if (localDigest == null || !digest.equals(localDigest)) {
                        EmbedNumberUtils.downOTAZipFile(url);
                        localDigest = getZipDigest(zipNumberFilePath);
                        if (!digest.equals(localDigest)) {
                            doXycallback(callBack, CallBackState.DOWNLOAD_FAILED, "digest mimatch");
                            return;
                        }
                    }

                    importEmbedNumberFileDataToDB(EmbedNumberUtils.unOTANumberZipAndReturnInputStream());
                    EmbedNumberUtils.setEmbedNumberVersion(mNewVersion);
                    doXycallback(callBack, CallBackState.HAS_DATA, mNewVersion);
                    /* IMOO-14 likuangkuang 20161018 start */
                    ParseNumberCache.removeAllCache();
                    /* IMOO-14 likuangkuang 20161018 end */
                } catch (Throwable e) {
                    LogManager.e(Constant.TAG, "UpgradeEmbedNumber fetchAndUpdate error:", e);
                    doXycallback(callBack, CallBackState.ERROR, "fetchAndUpdate unknown");
                }
            }
        });
    }

    private static void queryByService(final XyCallBack callBack) {
        Map<String, String> queryMap = new HashMap<String, String>();
        queryMap.put(EmbedNumberUtils.KEY_DATA_QUERY_VERSION, EmbedNumberUtils.getEmbedNumberVersion());
        UpgradeNumberService.queryByService(queryMap, null, new XyCallBack() {

            @Override
            public void execute(Object... obj) {
                try {
                    if (obj == null || obj.length < 2) {
                        doXycallback(callBack, CallBackState.ERROR, "obj invalid");
                        return;
                    }

                    int callBackState = (Integer) obj[0];
                    Object result = obj[1];
                    if (callBackState != CallBackState.HAS_DATA) {
                        doXycallback(callBack, callBackState, "query fail");
                        return;
                    }

                    JSONObject resultJson = (JSONObject) result;
                    int status = resultJson.optInt(KEY_STATUS);
                    switch (status) {
                    case STATUS_DATA_AVAILABLE:
                        fetchAndUpdate(callBack, resultJson);
                        break;

                    case STATUS_DATA_NOT_FOUND:
                    case STATUS_DATA_NOT_AVAILABLE:
                    default:
                        doXycallback(callBack, CallBackState.NO_DATA, EmbedNumberUtils.getEmbedNumberVersion());
                        break;
                    }

                } catch (Throwable e) {
                    doXycallback(callBack, CallBackState.ERROR, "query error");
                } finally {
                }
            }
        });
    }

    private static void doXycallback(final XyCallBack callBack, int state, String message) {
        LogManager.e(Constant.TAG, "upgrade callback:" + state + "/" + message);
        XyUtil.doXycallBackResult(callBack, state, message);
    }
}
